// © 2022 and later: Unicode, Inc. and others.
// License & terms of use: https://www.unicode.org/copyright.html

package com.ibm.icu.dev.test.message2;

import com.ibm.icu.dev.test.CoreTestFmwk;
import com.ibm.icu.message2.FormattedPlaceholder;
import com.ibm.icu.message2.Function;
import com.ibm.icu.message2.FunctionFactory;
import com.ibm.icu.message2.MFFunctionRegistry;
import com.ibm.icu.message2.MessageFormatter;
import com.ibm.icu.message2.PlainStringFormattedValue;
import java.util.Locale;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Showing a custom function that can handle grammatical cases. */
@RunWith(JUnit4.class)
@SuppressWarnings({"static-method", "javadoc"})
public class CustomFunctionGrammarCaseTest extends CoreTestFmwk {

    static class GrammarCasesFunctionFactory implements FunctionFactory {

        @Override
        public Function create(Locale locale, Map<String, Object> fixedOptions) {
            Object grammarCase = fixedOptions.get("case");
            return new GrammarCasesFunctionImpl(grammarCase == null ? "" : grammarCase.toString());
        }

        static class GrammarCasesFunctionImpl implements Function {
            final String grammarCase;

            GrammarCasesFunctionImpl(String grammarCase) {
                this.grammarCase = grammarCase;
            }

            // Romanian naive and incomplete rules, just to make things work for testing.
            private static String getDativeAndGenitive(String value) {
                if (value.endsWith("ana")) {
                    return value.substring(0, value.length() - 3) + "nei";
                }
                if (value.endsWith("ca")) {
                    return value.substring(0, value.length() - 2) + "căi";
                }
                if (value.endsWith("ga")) {
                    return value.substring(0, value.length() - 2) + "găi";
                }
                if (value.endsWith("a")) {
                    return value.substring(0, value.length() - 1) + "ei";
                }
                return "lui " + value;
            }

            @Override
            public String formatToString(Object toFormat, Map<String, Object> variableOptions) {
                return format(toFormat, variableOptions).toString();
            }

            @Override
            public FormattedPlaceholder format(
                    Object toFormat, Map<String, Object> variableOptions) {
                String result;
                if (toFormat == null) {
                    result = null;
                } else if (toFormat instanceof CharSequence) {
                    String value = (String) toFormat;
                    switch (grammarCase) {
                        case "dative": // intentional fallback
                        case "genitive":
                            result = getDativeAndGenitive(value);
                            // and so on for other cases, but I don't care to add more for now
                            break;
                        default:
                            result = value;
                    }
                } else {
                    result = toFormat.toString();
                }
                return new FormattedPlaceholder(toFormat, new PlainStringFormattedValue(result));
            }
        }
    }

    static final MFFunctionRegistry REGISTRY =
            MFFunctionRegistry.builder()
                    .setFunction("grammarBB", new GrammarCasesFunctionFactory())
                    .build();

    @Test
    public void test() {
        MessageFormatter mf =
                MessageFormatter.builder()
                        .setFunctionRegistry(REGISTRY)
                        .setLocale(Locale.forLanguageTag("ro"))
                        .setPattern("Cartea {$owner :grammarBB case=genitive}")
                        .build();

        assertEquals(
                "case - genitive", "Cartea Mariei", mf.formatToString(Args.of("owner", "Maria")));
        assertEquals(
                "case - genitive", "Cartea Rodicăi", mf.formatToString(Args.of("owner", "Rodica")));
        assertEquals(
                "case - genitive", "Cartea Ilenei", mf.formatToString(Args.of("owner", "Ileana")));
        assertEquals(
                "case - genitive",
                "Cartea lui Petre",
                mf.formatToString(Args.of("owner", "Petre")));

        mf =
                MessageFormatter.builder()
                        .setFunctionRegistry(REGISTRY)
                        .setLocale(Locale.forLanguageTag("ro"))
                        .setPattern("M-a sunat {$owner :grammarBB case=nominative}")
                        .build();

        assertEquals(
                "case - nominative",
                "M-a sunat Maria",
                mf.formatToString(Args.of("owner", "Maria")));
        assertEquals(
                "case - nominative",
                "M-a sunat Rodica",
                mf.formatToString(Args.of("owner", "Rodica")));
        assertEquals(
                "case - nominative",
                "M-a sunat Ileana",
                mf.formatToString(Args.of("owner", "Ileana")));
        assertEquals(
                "case - nominative",
                "M-a sunat Petre",
                mf.formatToString(Args.of("owner", "Petre")));
    }
}
